package configure

import (
	"fmt"
	"gitee.com/kristas/booting-go/framework/common/util/config_merge"
	"gitee.com/kristas/booting-go/framework/common/util/lang"
	"gopkg.in/yaml.v3"
)

//ConfigReader returns byte array only support json and yaml
//type ConfigReader func(environment string) []byte

var (
	_config = make(map[string]interface{})
	loaders = []ConfigLoader{&localConfigLoader{}}
)

func AddConfigReader(loader ConfigLoader) {
	loaders = append(loaders, loader)
}

func GetConfig() map[string]interface{} {
	return _config
}

func Init(environment string) {
	for _, loader := range loaders {
		bytes, err := loader.Load(environment)
		if err != nil {
			panic(err)
		}
		SetConfig(bytes)
		go func() {
			err := loader.RegisterListener(environment)
			if err != nil {
				fmt.Println("register config listener failed: " + err.Error())
			}
		}()
	}
}

func SetConfig(config []byte) {
	var tmp = make(map[string]interface{})
	err := yaml.Unmarshal(config, tmp)
	if err != nil {
		panic(err)
	}
	_config = config_merge.MergeMap(_config, tmp)
}

func UpdateConfig() {
	//beans := bean_factory.GetApplicationContext().GetAllBeans()
	//for _, bean := range beans {
	//	Bind(bean)
	//}
}

func CompileVariable() {
	compileVariable(_config)
}

func compileVariable(m map[string]interface{}) {
	lp := "${"
	rp := "}"
	for k, v := range m {
		switch v.(type) {
		case map[string]interface{}:
			compileVariable(v.(map[string]interface{}))
		case string:
			s := lang.NewString(v)
			matches, err := s.FindByPattern(`\${[^}]+}`)
			if err != nil {
				panic(err)
			}
			for _, match := range matches {
				s2 := lang.NewString(match).RemovePrefix(lp).RemoveSuffix(rp).String()
				variable := Get(s2)
				switch variable.(type) {
				case map[string]interface{}:
					m[k] = variable
				default:
					m[k] = s.Replace(match, fmt.Sprintf("%v", variable), 1)
				}
			}
		}
	}
}
